/* fontman.c: TeX Font Manager. */

#include "fontman.h"

int  print_usage();
void print_actions(struct action *actions);
void print_action_desc(struct action *act);
int  do_help(int argc, char *argv[]);
int  do_list(int argc, char *argv[]);
int  do_info(int argc, char *argv[]);

struct action_desc help_desc = { 
    "Describe the usage of this program or its actions.", 
    "[ACTIONS...]", 
    NULL
};

struct action_desc info_desc = {
    "Get the information of a specific font.", 
    "<FONT NAME>\n\n"
    "  The font name must be given in a non-ambiguous form. That is,\n"
    "  you must spell the complete font name or PostScript name, when\n"
    "  in doubt, use the list action to make sure.\n", 
    "  -f               : the FONT NAME given is a file name, rather \n"
    "                   : than a font name\n"
};

struct action_desc install_desc = { 
    "Install a specific font to be used by your TeX system.", 
    "<FONT NAME>", 
    NULL
};

struct action_desc list_desc = { 
    "List all/matching fonts in your operating system.", 
    "[PATTERN]\n\n"
    "  If no PATTERN given, list all fonts available. With option -d\n"
    "  specified, fonts are restricted to the given directory,\n"
    "  otherwise, fonts are queried from your local operating system\n"
    "  API. Normally, when listing system fonts, fonts without a local\n"
    "  name is omitted, but you can use -a option to show them.\n", 
    "  -d arg           : limit font listing within the directory \n"
    "                     specified by ARG\n"
    "  -p               : show PostScript name of fonts\n"
    "  -l               : try to get local (non-ascii) font name if\n"
    "                     possible\n"
    "  -a               : show all available fonts\n"
};

struct action_desc remove_desc = { 
    "Remove a specific font from your TeX installation.", 
    "<font name>", 
    NULL, 
};

struct action fontman_actions[] = {
    { "help",    "h",  do_help, &help_desc    },
    { "info",    "i",  do_info, &info_desc    },  
    { "install", NULL, NULL,    &install_desc }, 
    { "list",    NULL, do_list, &list_desc    },
    { "remove",  NULL, NULL,    &remove_desc  }, 
    { NULL,      NULL, NULL,    NULL          }, 
};

int main(int argc, char *argv[])
{
    struct action *act;
    int i;

    if (argc < 2)
    {
        fprintf(stderr, "Type '%s help' for usage.\n", 
                FONTMAN_PROG_NAME);
        return 1;
    }

    loop_actions(i, act, fontman_actions)
    {
        if ((str_equal(act->full_name, argv[1]) ||
             str_equal(act->short_name, argv[1])) &&
            act->func != NULL)
            return act->func(argc - 2, argv + 2);
    }

    fprintf(stderr, "Unknown command: '%s'\n"
                    "Type '%s help' for usage.\n", 
            argv[1], FONTMAN_PROG_NAME);
    return 1;
}

int print_usage()
{
    printf("usage: %s <action> [options] [args]\n"
           "TeX Font Manager, version %d.%d.%d, backend %s.\n"
           "Type '%s help <action>' for help on a specific action.\n\n"
           "Available actions:\n", 
           FONTMAN_PROG_NAME, 
           FONTMAN_VER_MAJOR, FONTMAN_VER_MINOR, FONTMAN_VER_REVISION, 
           fontman_get_backend(),
           FONTMAN_PROG_NAME);

    print_actions(fontman_actions);

    printf("\nManage TeX fonts and interact with system, including list\n"
           "system fonts, install a specific font for TeX, remove one, \n"
           "etc. \n");

    return 0;
}

void print_actions(struct action *actions)
{
    struct action *act;
    int i;

    loop_actions(i, act, actions)
    {
        printf("  %s", act->full_name);
        if (act->short_name != NULL)
            printf(" (%s)", act->short_name);

        printf("\n");
    }
}

int do_help(int argc, char *argv[])
{
    char *act_name; 
    struct action *act;
    int i;

    if (! argc)
        return print_usage();
    
    act_name = argv[0];
    loop_actions(i, act, fontman_actions)
    {
        if ((str_equal(act->full_name, act_name) ||
             str_equal(act->short_name, act_name)) &&
            act->desc != NULL)
        {
            print_action_desc(act);
            return 0;
        }
    }

    fprintf(stderr, "\"%s\": unknown action.\n", act_name);
    return 1;
}

void print_action_desc(struct action *act)
{
    struct action_desc *desc;

    printf("%s", act->full_name);
    if (act->short_name != NULL)
        printf(" (%s)", act->short_name);

    desc = act->desc;
    if (desc->brief)
        printf(": %s\n", desc->brief);
    else
        printf("\n");

    if (desc->usage)
        printf("usage: %s %s\n", act->full_name, desc->usage);

    if (desc->options)
        printf("Valid options:\n%s", desc->options);

    printf("\n");
}

int do_list(int argc, char *argv[])
{
    const char *dir = NULL, *pattern = NULL;
    fontman_face_t face;
    unsigned int flags = FONTMAN_GET_NAME;

    while (argc > 0 && argv[0][0] == '-')
    {
        if (has_opt(2, "-d"))
        {
            dir = argv[1];
            argc -= 2;
            argv += 2;
        }

        if (has_opt(1, "-p"))
        {
            flags |= FONTMAN_GET_PS_NAME;
            argc -= 1;
            argv += 1;
        }

        if (has_opt(1, "-l"))
        {
            flags |= FONTMAN_GET_LOCAL_NAME;
            argc -= 1;
            argv += 1;
        }
        
        if (has_opt(1, "-a"))
        {
            flags |= FONTMAN_INCLUDE_ALL;
            argc -= 1;
            argv += 1;
        }
    }

    if (argc > 0)
        pattern = argv[0];

    fontman_list_init(dir == NULL ? FONTMAN_LIST_SYSTEM 
                                  : FONTMAN_LIST_PATH, 
                      dir, pattern, flags);

    printf("Available fonts in %s", str_or(dir, "your system"));

    if (pattern)
        printf(" matched \"%s\"", pattern);

    printf(":\n\n");

    while (fontman_list_next(&face) == 0)
    {
        printf("%-50s", (flags & FONTMAN_GET_LOCAL_NAME && 
                         strlen(face.local_name)) ? face.local_name 
                                                  : face.name);
        if (flags & FONTMAN_GET_PS_NAME)
            printf(": %s", face.ps_name);
        
        printf("\n");
    }

    fontman_list_free();
    return 0;
}

int do_info(int argc, char *argv[])
{
    enum fontman_info_type type;
    fontman_face_t face;
    int err, i;

    type = FONTMAN_INFO_SYSTEM;
    while (argc > 0 && argv[0][0] == '-')
    {
        if (has_opt(1, "-f"))
        {
            type = FONTMAN_INFO_FILE;
            argc -= 1;
            argv += 1;
        }

        if (has_opt(1, "-t"))
        {
            type = FONTMAN_INFO_TEX_FONT;
            argc -= 1;
            argv += 1;
        }
    }

    if (argc <= 0)
    {
        fprintf(stderr, "%s: Not enough arguments provided; "
                "try '%s help' for more info\n", 
                FONTMAN_PROG_NAME, FONTMAN_PROG_NAME);
        return 1;
    }

    if (type == FONTMAN_INFO_FILE)
        strncpy(face.path, argv[0], PATH_MAX - 1);
    else
        strncpy(face.name, argv[0], FONTMAN_MAX_FONT_NAME - 1);

    if ((err = fontman_info(&face, type)))
    {
        fprintf(stderr, "%s: get font info failed: %s\n", 
                FONTMAN_PROG_NAME, fontman_error_msg(err));
        return 1;
    }

    printf("Name            : %s\n", face.name);
    printf("PostScript name : %s\n", face.ps_name);
    printf("Local name      : %s\n", face.local_name);
    printf("Path            : %s\n", face.path);

    printf("Family name     : %s\n", face.extra->family);
    printf("Style           : %s\n", face.extra->style);
    printf("Glyph number    : %ld\n", face.extra->num_glyphs);

    printf("Charmaps        : %d\n", face.extra->num_charmaps);
    for (i = 0; i < face.extra->num_charmaps; i++)
    {
        unsigned short pid, eid;

        pid = face.extra->charmaps[i]->pid;
        eid = face.extra->charmaps[i]->eid;

        printf("+ %s (%d), ", 
               fontman_get_platform(pid), pid);

        if (pid == FONTMAN_ENCODING_APPLE && 
            eid <= FONTMAN_MAX_APPLE_ENCODING)
            printf("%s (%d)", fontman_get_apple_encoding(eid), eid);
        else
        if (pid == FONTMAN_ENCODING_MS &&
            pid <= FONTMAN_MAX_MS_ENCODING)
            printf("%s (%d)", fontman_get_ms_encoding(eid), eid);
        else
            printf("%d", eid);

        printf("\n");
    }

    fontman_info_done(&face);

    return 0;
}

